use crate::domain::events::{EventDispatcher, FTPEvent, FTPEventPayload, HttpEventDispatcher};
use async_trait::async_trait;
use clap::ArgMatches;
use libnftp::notification::{DataEvent, DataListener, EventMeta};
use std::sync::Arc;

pub(crate) fn create_event_dispatcher(arg_matches: &ArgMatches) -> Result<Arc<dyn EventDispatcher<FTPEvent>>, String> {
    Ok(Arc::new(HttpEventDispatcher::new(arg_matches)))
}

#[derive(Debug)]
pub struct FTPListener {
    pub event_dispatcher: Arc<dyn EventDispatcher<FTPEvent>>,
    pub instance_name: String,
    pub hostname: String,
}

impl FTPListener {
    async fn dispatch(&self, payload: FTPEventPayload, m: EventMeta) {
        self.event_dispatcher
            .dispatch(FTPEvent {
                source_instance: self.instance_name.clone(),
                hostname: self.hostname.clone(),
                payload,
                username: Some(m.username),
                trace_id: Some(m.trace_id),
                sequence_number: Some(m.sequence_number),
            })
            .await;
    }
}

#[async_trait]
impl DataListener for FTPListener {
    async fn receive_data_event(&self, e: DataEvent, m: EventMeta) {
        let payload = match e {
            DataEvent::Got { path, .. } => FTPEventPayload::Get { path },
            DataEvent::Put { path, .. } => FTPEventPayload::Put { path },
            DataEvent::Deleted { path } => FTPEventPayload::Delete { path },
            DataEvent::MadeDir { path } => FTPEventPayload::MakeDir { path },
            DataEvent::Renamed { from, to } => FTPEventPayload::Rename { from, to },
            DataEvent::RemovedDir { path } => FTPEventPayload::RemoveDir { path },
        };
        self.dispatch(payload, m).await;
    }
}
